package com.platform.tony.config;


import com.platform.tony.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * spring security 配置信息
 */

@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConf extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "authServiceImpl")
    private UserDetailsService userDetailsService;

    @Autowired
    private UserService userService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private AppSuccessHandler successHandler;

    @Autowired
    private AppFailureHandler failureHandler;

//    @Autowired
//    private PhoneCodeFilter phoneCodeFilter;

    @Autowired
    private StringRedisTemplate template;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        // InMemoryTokenRepositoryImpl node = new InMemoryTokenRepositoryImpl();
        JdbcTokenRepositoryImpl node = new JdbcTokenRepositoryImpl();
        node.setCreateTableOnStartup(false);
        node.setDataSource(dataSource);
        return node;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {

        // super.configure(web);
    }

    // 邮箱认证过滤器
    @Bean
    public EmailAuthFilter emailAuthFilter() throws Exception {
        // 手机号登录拦截器
        EmailAuthFilter emailAuthFilter = new EmailAuthFilter();
        emailAuthFilter.setAuthenticationManager(authenticationManagerBean());
        emailAuthFilter.setAuthenticationSuccessHandler(successHandler);
        emailAuthFilter.setAuthenticationFailureHandler(failureHandler);
        emailAuthFilter.setTemplate(template);
        return emailAuthFilter;
    }

    //
    @Bean
    public EmailAuthProvider emailAuthProvider() {
        return new EmailAuthProvider(userService);
    }

    // 过滤器配置
    @Bean
    public PhoneAuthFilter phoneAuthFilter() throws Exception {
        // 手机号登录拦截器
        PhoneAuthFilter phoneAuthFilter = new PhoneAuthFilter();
        phoneAuthFilter.setAuthenticationManager(authenticationManagerBean());
        phoneAuthFilter.setAuthenticationSuccessHandler(successHandler);
        phoneAuthFilter.setAuthenticationFailureHandler(failureHandler);
        phoneAuthFilter.setTemplate(template);
        return phoneAuthFilter;
    }

    // 认证 provider 配置
    @Bean
    public PhoneAuthProvider phoneAuthProvider() {
        return new PhoneAuthProvider(userService);
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());

        // 手机号登录方式
        auth.authenticationProvider(phoneAuthProvider());
        // 邮箱登录方式
        auth.authenticationProvider(emailAuthProvider());
        // 微信方式登录
        auth.authenticationProvider(new WeChatAuthProvider(userService));

        DaoAuthenticationProvider dao = new DaoAuthenticationProvider();
        dao.setPasswordEncoder(passwordEncoder());
        dao.setUserDetailsService(userDetailsService);
        // 账号密码登录方式
        auth.authenticationProvider(dao);

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // 关闭 csrf 攻击
        http.csrf().disable();
        // 开启跨域访问
        http.cors().disable();
        // 配置认证信息
        http.authorizeRequests()
                .antMatchers("/login/form", "/login", "/auth", "/api/**").permitAll()
                .antMatchers("/**/*.js", "*.jpg", "/**/*.css").permitAll()
                .mvcMatchers("/vc.jpg").permitAll()
                .anyRequest().authenticated();

        // 添加拦截器配置
        http.addFilterBefore(phoneAuthFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(emailAuthFilter(), UsernamePasswordAuthenticationFilter.class);

        // 添加动态验证码
        // http.addFilterAt(kaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
        // 不使用 session
        // http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // session 管理
        http.sessionManagement().maximumSessions(3);
        // 用户名密码登录 form 表单处理
        http.formLogin()
                .loginPage("/login")
                .failureForwardUrl("/login")
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .passwordParameter("password")
                .usernameParameter("username")
                // .successForwardUrl("/home") 转发的方式
                .defaultSuccessUrl("/home")  // 重定向
                .loginProcessingUrl("/login/form"); // 登录请求处理地址
        // 权限不足
        http.exceptionHandling().accessDeniedPage("/403");
        // 记录登录
        http.rememberMe()
                .rememberMeParameter("rememberMe")
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(30 * 60)
                .userDetailsService(userDetailsService);

    }

    @Bean
    public KaptchaFilter kaptchaFilter() throws Exception {
        KaptchaFilter kaptchaFilter = new KaptchaFilter();
        //指定接收验证码请求参数名
        kaptchaFilter.setKaptcha("kaptcha");
        //指定认证管理器
        kaptchaFilter.setAuthenticationManager(authenticationManagerBean());
        //指定认证成功和失败处理
        // kaptchaFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
        // kaptchaFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());

        //指定处理登录
        kaptchaFilter.setFilterProcessesUrl("/login/form");
        kaptchaFilter.setUsernameParameter("username");
        kaptchaFilter.setPasswordParameter("password");
        return kaptchaFilter;
    }

    @Override
    @Bean(value = "authenticationManager")
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        // BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(20);
        // String encode = encoder.encode("123456");
        // boolean matches = encoder.matches("123456", encode);
        // System.out.println("match result " + matches);
        return NoOpPasswordEncoder.getInstance();
    }


}
